﻿using System.Collections.Generic;
using System.Linq;

namespace Sidvall.Data
{
    public sealed class FilterItem : FieldValueItem, IFilterItem
    {
        #region Public Members

        public ComparisonOperator ComparisonOperator { get; set; }

        #region Copy

        public FilterItem Copy()
        {
            return new FilterItem(this.FieldName, this.ComparisonOperator, this.Value, this.ValueDataType, this.ValueIsArray);
        }

        #endregion
        #region SetFilter

        public void SetFilter(ComparisonOperator comparisonOperator, object value, DataType dataType)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = dataType;
            this.ValueIsArray = false;
            this.Value = Sidvall.Serialization.SerializerManager.Current.SerializeObject(value, this.ValueDataType);
        }
        public void SetFilter(ComparisonOperator comparisonOperator, bool value)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = DataType.Boolean;
            this.ValueIsArray = false;
            this.Value = Sidvall.Serialization.SerializerManager.Current.Serialize(value);
        }
        public void SetFilter(ComparisonOperator comparisonOperator, byte value)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = DataType.Byte;
            this.ValueIsArray = false;
            this.Value = Sidvall.Serialization.SerializerManager.Current.Serialize(value);
        }
        public void SetFilter(ComparisonOperator comparisonOperator, char value)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = DataType.Char;
            this.ValueIsArray = false;
            this.Value = Sidvall.Serialization.SerializerManager.Current.Serialize(value);
        }
        public void SetFilter(ComparisonOperator comparisonOperator, System.DateTime value)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = DataType.DateTime;
            this.ValueIsArray = false;
            this.Value = Sidvall.Serialization.SerializerManager.Current.Serialize(value);
        }
        public void SetFilter(ComparisonOperator comparisonOperator, System.DateTimeOffset value)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = DataType.DateTimeOffset;
            this.ValueIsArray = false;
            this.Value = Sidvall.Serialization.SerializerManager.Current.Serialize(value);
        }
        public void SetFilter(ComparisonOperator comparisonOperator, System.Guid value)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = DataType.Guid;
            this.ValueIsArray = false;
            this.Value = Sidvall.Serialization.SerializerManager.Current.Serialize(value);
        }
        public void SetFilter(ComparisonOperator comparisonOperator, decimal value)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = DataType.Decimal;
            this.ValueIsArray = false;
            this.Value = Sidvall.Serialization.SerializerManager.Current.Serialize(value);
        }
        public void SetFilter(ComparisonOperator comparisonOperator, double value)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = DataType.Double;
            this.ValueIsArray = false;
            this.Value = Sidvall.Serialization.SerializerManager.Current.Serialize(value);
        }
        public void SetFilter(ComparisonOperator comparisonOperator, short value)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = DataType.Int16;
            this.ValueIsArray = false;
            this.Value = Sidvall.Serialization.SerializerManager.Current.Serialize(value);
        }
        public void SetFilter(ComparisonOperator comparisonOperator, int value)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = DataType.Int32;
            this.ValueIsArray = false;
            this.Value = Sidvall.Serialization.SerializerManager.Current.Serialize(value);
        }
        public void SetFilter(ComparisonOperator comparisonOperator, long value)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = DataType.Int64;
            this.ValueIsArray = false;
            this.Value = Sidvall.Serialization.SerializerManager.Current.Serialize(value);
        }
        public void SetFilter(ComparisonOperator comparisonOperator, float value)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = DataType.Single;
            this.ValueIsArray = false;
            this.Value = Sidvall.Serialization.SerializerManager.Current.Serialize(value);
        }
        public void SetFilter(ComparisonOperator comparisonOperator, string value)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = DataType.String;
            this.ValueIsArray = false;
            this.Value = Sidvall.Serialization.SerializerManager.Current.Serialize(value);
        }
        public void SetFilter(ComparisonOperator comparisonOperator, System.TimeSpan value)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = DataType.TimeSpan;
            this.ValueIsArray = false;
            this.Value = Sidvall.Serialization.SerializerManager.Current.Serialize(value);
        }
        public void SetFilter(ComparisonOperator comparisonOperator, byte[] value)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = DataType.Binary;
            this.ValueIsArray = false;
            this.Value = Sidvall.Serialization.SerializerManager.Current.Serialize(value);
        }
        public void SetFilter(ComparisonOperator comparisonOperator, Sidvall.Data.Geography value)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = DataType.Geography;
            this.ValueIsArray = false;
            this.Value = Sidvall.Serialization.SerializerManager.Current.Serialize(value);
        }
        public void SetFilter(ComparisonOperator comparisonOperator, Sidvall.Data.Geometry value)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = DataType.Geometry;
            this.ValueIsArray = false;
            this.Value = Sidvall.Serialization.SerializerManager.Current.Serialize(value);
        }
        public void SetFilter(ComparisonOperator comparisonOperator, System.Enum value)
        {
            System.Type enumType, valueType;
            object enumValue;

            if (value == null)
                return;
            enumType = value.GetType();
            if (!System.Enum.IsDefined(enumType, value))
                return;
            valueType = System.Enum.GetUnderlyingType(enumType);
            enumValue = System.Enum.Parse(enumType, value.ToString(), true);

            this.ComparisonOperator = comparisonOperator;
            this.ValueIsArray = false;
            if (valueType == typeof(System.Byte))
            {
                this.ValueDataType = DataType.Byte;
                this.Value = Sidvall.Serialization.SerializerManager.Current.Serialize((byte)enumValue);
            }
            else if (valueType == typeof(System.Int16))
            {
                this.ValueDataType = DataType.Int16;
                this.Value = Sidvall.Serialization.SerializerManager.Current.Serialize((short)enumValue);
            }
            else if (valueType == typeof(System.Int32))
            {
                this.ValueDataType = DataType.Int32;
                this.Value = Sidvall.Serialization.SerializerManager.Current.Serialize((int)enumValue);
            }
            else if (valueType == typeof(System.Int64))
            {
                this.ValueDataType = DataType.Int64;
                this.Value = Sidvall.Serialization.SerializerManager.Current.Serialize((long)enumValue);
            }
        }
        public void SetFilter(ComparisonOperator comparisonOperator, IEnumerable<byte> value)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = DataType.Byte;
            this.ValueIsArray = true;
            this.Value = Sidvall.Serialization.SerializerManager.Current.SerializeArray(value);
        }
        public void SetFilter(ComparisonOperator comparisonOperator, IEnumerable<short> value)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = DataType.Int16;
            this.ValueIsArray = true;
            this.Value = Sidvall.Serialization.SerializerManager.Current.SerializeArray(value);
        }
        public void SetFilter(ComparisonOperator comparisonOperator, IEnumerable<int> value)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = DataType.Int32;
            this.ValueIsArray = true;
            this.Value = Sidvall.Serialization.SerializerManager.Current.SerializeArray(value);
        }
        public void SetFilter(ComparisonOperator comparisonOperator, IEnumerable<long> value)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = DataType.Int64;
            this.ValueIsArray = true;
            this.Value = Sidvall.Serialization.SerializerManager.Current.SerializeArray(value);
        }
        public void SetFilter(ComparisonOperator comparisonOperator, IEnumerable<string> value)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = DataType.String;
            this.ValueIsArray = true;
            this.Value = Sidvall.Serialization.SerializerManager.Current.SerializeArray(value);
        }
        public void SetFilter(ComparisonOperator comparisonOperator, IEnumerable<System.Guid> value)
        {
            this.ComparisonOperator = comparisonOperator;
            this.ValueDataType = DataType.Guid;
            this.ValueIsArray = true;
            this.Value = Sidvall.Serialization.SerializerManager.Current.SerializeArray(value);
        }
        public void SetFilter<T>(ComparisonOperator comparisonOperator, IEnumerable<T> value) where T : struct
        {
            System.Type enumType, valueType;

            if (value == null)
                return;
            enumType = value.GetType().GenericTypeArguments[0];
            valueType = System.Enum.GetUnderlyingType(enumType);

            this.ComparisonOperator = comparisonOperator;
            this.ValueIsArray = true;
            if (valueType == typeof(System.Byte))
            {
                this.ValueDataType = DataType.Byte;
                this.Value = Sidvall.Serialization.SerializerManager.Current.SerializeArray(value.Cast<byte>());
            }
            else if (valueType == typeof(System.Int16))
            {
                this.ValueDataType = DataType.Int16;
                this.Value = Sidvall.Serialization.SerializerManager.Current.SerializeArray(value.Cast<short>());
            }
            else if (valueType == typeof(System.Int32))
            {
                this.ValueDataType = DataType.Int32;
                this.Value = Sidvall.Serialization.SerializerManager.Current.SerializeArray(value.Cast<int>());
            }
            else if (valueType == typeof(System.Int64))
            {
                this.ValueDataType = DataType.Int64;
                this.Value = Sidvall.Serialization.SerializerManager.Current.SerializeArray(value.Cast<long>());
            }
        }

        #endregion
        #region ToString

        public override string ToString()
        {
            return Sidvall.SystemContext.Current.SqlManager.GetSqlWhere(this);
        }

        #endregion

        #region IFilterItem Members

        object IFilterItem.Value
        {
            get
            {
                return GetFieldValue();
            }
        }
        LogicalOperator IFilterItem.LogicalOperator
        {
            get
            {
                return Data.LogicalOperator.And;
            }
            set
            {
            }
        }
        ICollection<IFilterItem> IFilterItem.GetSubFilters()
        {
            return null;
        }

        #endregion

        #endregion
        #region Constructors

        public FilterItem()
        {
        }
        public FilterItem(string fieldName, ComparisonOperator comparisonOperator, string value, DataType valueDataType, bool valueIsArray)
            : base(fieldName, value, valueDataType, valueIsArray)
        {
            this.ComparisonOperator = comparisonOperator;
        }

        #endregion
    }
}
